package cn.coder.toolkit;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;

/**
 * 需要如下依赖
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk18on</artifactId>
    <version>1.82</version>
</dependency>
 */

@Slf4j
public final class SM4Kit {

    static {
        Security.addProvider(new BouncyCastleProvider()); // 注册 BouncyCastle 提供者
    }

    private SM4Kit() {}

    // 前端 CryptoJS 风格：SM4/CBC/PKCS7
    // Key 长度必须是 16 字节（128 位）。IV 长度也必须是 16 字节。
    private static final String SM4_CBC_PKCS7 = "SM4/CBC/PKCS7Padding"; // CBC（带 IV）, ECB（无 IV）较弱, 不在生产中使用
    private static final String SM4 = "SM4";

    private static final SecureRandom RANDOM = new SecureRandom();

    public static String toBase64(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }

    public static byte[] fromBase64(String base64) {
        return Base64.getDecoder().decode(base64);
    }

    /**
     * key 和 iv 都可以由此生成, 长度都为 16 bytes
     */
    public static byte[] genKeyOrIv() {
        byte[] bytes = new byte[16];
        RANDOM.nextBytes(bytes);
        return bytes;
    }

    public static byte[] encrypt(byte[] key, byte[] iv, byte[] data) {
        try {
            Cipher cipher = Cipher.getInstance(SM4_CBC_PKCS7, BouncyCastleProvider.PROVIDER_NAME);
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, SM4), new IvParameterSpec(iv));
            return cipher.doFinal(data);
        } catch (NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] decrypt(byte[] key, byte[] iv, byte[] data) {
        try {
            Cipher cipher = Cipher.getInstance(SM4_CBC_PKCS7, BouncyCastleProvider.PROVIDER_NAME);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, SM4), new IvParameterSpec(iv));
            return cipher.doFinal(data);
        } catch (NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        byte[] key = genKeyOrIv();
        byte[] iv = genKeyOrIv();
        byte[] data = "123456781234567899999999999999999999999999999999999999999999999999999999999999999999999999999999".getBytes();
        byte[] encrypted = encrypt(key, iv, data);
        byte[] decrypted = decrypt(key, iv, encrypted);
        log.info("SM4 解密结果：{}", new String(decrypted));
    }

}
